package sicnu.cs.ich.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.NoSuchFileException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 沈洋 邮箱:1845973183@qq.com
 * @create 2021/11/30-15:22
 **/
@Slf4j
public class  FileUtils extends org.apache.commons.io.FileUtils {
    private final static String IMG_JPG = "image/jpeg";
    private final static String IMG_PNG = "image/png";

    /**
     * 校验文件数组是否为图片（注意）
     */
    public static List<MultipartFile> isImage(MultipartFile... files) throws IOException {
        List<MultipartFile> fileList = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {
            if (!isImage(files[i])) {
                files[i] = null;
            }else{
                fileList.add(files[i]);
            }
        }
        if (fileList.size()==0){
            throw new NoSuchFileException("无有效文件");
        }
        return fileList;
    }
    public static boolean isImage(MultipartFile file) throws IOException {
        // 文件为空直接返回false
        if (file==null) return false;
        String contentType = file.getContentType();
        // 校验后缀是否为图片后缀
        if (StringUtils.isBlank(contentType)
                ||(!IMG_JPG.equals(contentType)&&(!IMG_PNG.equals(contentType)))){
            return false;
        }
        // 校验魔数
        return !illegalFile(file.getInputStream());
    }

    /**
     * 字节转换
     */
    public static long mbTob(int mb){
        return (long) mb*1024L*1024L;
    }

    public static boolean isEmpty(MultipartFile... files) {
        for (MultipartFile file : files) {
            if (file==null||file.isEmpty()){
                return true;
            }
        }
        return false;
    }


    // 默认判断文件头前三个字节内容
    public static int DEFAULT_CHECK_LENGTH = 3;
    final static HashMap<String, String> fileTypeMap = new HashMap<>();

    // 初始化文件头类型，不够的自行补充
    static {
        fileTypeMap.put("ffd8ff", "jpg");
        fileTypeMap.put("89504e", "png");
        fileTypeMap.put("474946", "gif");
        fileTypeMap.put("49492a", "tif");
        fileTypeMap.put("424d22", "bmp");
        fileTypeMap.put("424d82", "bmp");
        fileTypeMap.put("424d8e", "bmp");
        fileTypeMap.put("414331", "dwg");
        fileTypeMap.put("3c2144", "html");
        fileTypeMap.put("3c2164", "htm");
        fileTypeMap.put("48544d", "css");
        fileTypeMap.put("696b2e", "js");
        fileTypeMap.put("7b5c72", "rtf");
        fileTypeMap.put("384250", "psd");
        fileTypeMap.put("46726f", "eml");
        fileTypeMap.put("d0cf11", "doc");
        fileTypeMap.put("537461", "mdb");
        fileTypeMap.put("252150", "ps");
        fileTypeMap.put("255044", "pdf");
        fileTypeMap.put("2e524d", "rmvb");
        fileTypeMap.put("464c56", "flv");
        fileTypeMap.put("000000", "mp4");
        fileTypeMap.put("494433", "mp3");
        fileTypeMap.put("000001", "mpg");
        fileTypeMap.put("3026b2", "wmv");
        fileTypeMap.put("524946", "wav");
        fileTypeMap.put("4d5468", "mid");
        fileTypeMap.put("504b03", "zip");
        fileTypeMap.put("526172", "rar");
        fileTypeMap.put("235468", "ini");
        fileTypeMap.put("4d5a90", "exe");
        fileTypeMap.put("3c2540", "jsp");
        fileTypeMap.put("4d616e", "mf");
        fileTypeMap.put("3c3f78", "xml");
        fileTypeMap.put("494e53", "sql");
        fileTypeMap.put("706163", "java");
        fileTypeMap.put("406563", "bat");
        fileTypeMap.put("1f8b08", "gz");
        fileTypeMap.put("6c6f67", "properties");
        fileTypeMap.put("cafeba", "class");
        fileTypeMap.put("495453", "chm");
        fileTypeMap.put("040000", "mxp");
        //fileTypeMap.put("504b03", "docx");
        fileTypeMap.put("643130", "torrent");
        fileTypeMap.put("6D6F6F", "mov");
        fileTypeMap.put("FF5750", "wpd");
        fileTypeMap.put("CFAD12", "dbx");
        fileTypeMap.put("214244", "pst");
        fileTypeMap.put("AC9EBD", "qdf");
        fileTypeMap.put("E38285", "pwl");
        fileTypeMap.put("2E7261", "ram");
    }

    /**
     * @param fileName 文件名
     * @return String
     * 通过文件后缀名获取文件类型
     * @author xyz
     */
    public static String getFileTypeBySuffix(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
    }

    /**
     * @param inputStream 输入流
     * @return String
     * @description 通过文件头魔数获取文件类型
     * @author xyz
     */
    public static String getFileTypeByMagicNumber(InputStream inputStream) {
        byte[] bytes = new byte[DEFAULT_CHECK_LENGTH];
        try {
            // 获取文件头前三位魔数的二进制
            inputStream.read(bytes, 0, bytes.length);
            // 文件头前三位魔数二进制转为16进制
            String code = bytesToHexString(bytes);
            for (Map.Entry<String, String> item : fileTypeMap.entrySet()) {
                if (code.equals(item.getKey())) {
                    return item.getValue();
                }
            }
        } catch (IOException ignored) {
            log.error("文件读取错误");
        }
        throw new IllegalArgumentException("文件不合法");
    }

    /**
     * 校验文件是否合法
     * @param inputStream 文件流
     * @return true 不合法 false 合法
     */
    public static boolean illegalFile(InputStream inputStream) {
        byte[] bytes = new byte[DEFAULT_CHECK_LENGTH];
        try {
            // 获取文件头前三位魔数的二进制
            inputStream.read(bytes, 0, bytes.length);
            // 文件头前三位魔数二进制转为16进制
            String code = bytesToHexString(bytes);
            return !fileTypeMap.containsKey(code);
        } catch (IOException ignored) {
            log.error("文件读取错误");
            throw new IllegalArgumentException("文件不合法");
        }
    }


    /**
     * @return String
     * @description 字节数组转为16进制
     * @author xyz
     */
    public static String bytesToHexString(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder();
        for (byte aByte : bytes) {
            int v = aByte & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

}
